package com.maycur.ctrip.util;

import Ice.Communicator;
import Ice.ObjectPrx;
import Ice.ObjectPrxHelperBase;
import Ice.Util;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by zhouchunjie on 16/2/14.
 */
@Component
public class IceClientUtil {
    private static final Logger logger = LoggerFactory.getLogger(IceClientUtil.class);

    private static final String ENDPOINT_CONFIG_PREFIX = "ice.service.endpoint.";

    private final Map<Class, ObjectPrx> cachedProxy = new ConcurrentHashMap<>();
    @Autowired
    Environment environment;
    private Communicator communicator;

    @PostConstruct
    public void init() {
        communicator = Util.initialize();
    }

    public <T extends ObjectPrx> T getServiceProxy(Class<? extends ObjectPrx> clazz) {

        ObjectPrx proxy = cachedProxy.get(clazz);
        if (proxy == null) {
            proxy = this.getServiceProxyInternal(clazz);
        }

        return (T) proxy;
    }

    private synchronized ObjectPrx getServiceProxyInternal(Class<? extends ObjectPrx> clazz) {

        if (cachedProxy.get(clazz) != null) {
            return cachedProxy.get(clazz);
        }

        String proxyClassName = clazz.getSimpleName();

        int index = proxyClassName.lastIndexOf("Prx");
        if (index < 0) {
            throw new IllegalArgumentException("Proxy class name must ends with Prx.");
        }

        String serviceName = proxyClassName.substring(0, index);

        String endpoint = environment.getProperty(ENDPOINT_CONFIG_PREFIX + serviceName);
        if (StringUtils.isBlank(endpoint)) {
            logger.error("Can't find endpoint configuration for {}", serviceName);
            throw new IllegalArgumentException("Can't find endpoint for " + serviceName);
        }

        ObjectPrx base = communicator.stringToProxy(serviceName + ":" + endpoint);

        try {

            ObjectPrxHelperBase serviceProxyHelper =
                (ObjectPrxHelperBase) base.getClass().forName(clazz.getName() + "Helper").newInstance();

            Method m1 = serviceProxyHelper.getClass().getDeclaredMethod("uncheckedCast", ObjectPrx.class);
            ObjectPrx proxy = (ObjectPrx) m1.invoke(serviceProxyHelper, base);

            logger.info("Put object proxy {}:{} to the cache. ", serviceName, endpoint);

            cachedProxy.put(clazz, proxy);

            return proxy;

        } catch (Exception ex) {
            logger.error("Exception happened during creating service proxy {}", ex.getMessage(), ex);
            throw new IllegalArgumentException("Can't create proxy class for " + proxyClassName, ex);
        }

    }

    @PreDestroy
    public void destroy() {
        if (communicator != null) {
            communicator.shutdown();
        }
    }
}
